﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Noris.Schedule.Support.Expressions;

namespace Noris.Schedule.Support.Services
{
	#region CLASS GraphElementDataCls : data pro jednotlivou položku grafu v řádku
	/// <summary>
	/// GraphElementDataCls : data pro jednotlivou položku grafu v řádku.
	/// Obsahuje jak data získaná z datového zdroje, tak data dopočítaná pro aktuální zobrazení.
	/// </summary>
	public class GraphElementDataCls
	{
		#region KONSTRUKCE
		/// <summary>
		/// Konstruktor
		/// </summary>
		/// <param name="dataElement"></param>
		public GraphElementDataCls(IDataElement dataElement, IDataRow dataRow)
		{
			this.DataElement = dataElement;
			this.DataRow = dataRow;
			this._PrepareConfiguredText();
		}
		/// <summary>
		/// Logická data o grafickém elementu.
		/// Jde o data, která vrátila datová vrstva.
		/// Obsahují zejména časový interval, typ údaje, specifikaci grafu, režim pohybu a další.
		/// </summary>
		public IDataElement DataElement { get; protected set; }
		/// <summary>
		/// Data řádku, který je hostitelem tohoto elementu
		/// </summary>
		public IDataRow DataRow { get; protected set; }
		/// <summary>
		/// Pointer na element = jeho logická adresa (řádek, element).
		/// </summary>
		public DataPointerStr DataPointer { get { return new DataPointerStr(this.DataElement.RowGId, this.DataElement.GId); } }
		/// <summary>
		/// Aktuální hodnota GID tohoto elementu. Je neměnná.
		/// </summary>
		public GID GId { get { return this.DataElement.GId; } }
		/// <summary>
		/// Specifikuje druh obsahu, ovlivňuje způsob zobrazování (barvu, vzhled).
		/// Datová vrstva zde může odlišovat různé typy směn, různé režimy práce, různé úrovně hierarchie zakázky, různé zobrazované třídy.
		/// U grafu typu RowGraphMode.Gantt ovlivní barvu políčka, vyjadřuje druh činnosti.
		/// U grafu typu RowGraphMode.CapacityUtilization ovlivní barvu políčka, vyjadřuje druh směny.
		/// U grafu typu RowGraphMode.TaskCapacityLink ovlivňuje barvu políčka směny (pokud je this.ElementLayer == SubLayer), nebo práce (pokud je this.ElementLayer == ItemLayer).
		/// Konkrétní barvu generuje metoda IDataSource.GetColorForElement()
		/// </summary>
		public GraphElementVisualType ElementVisualType { get { return this.DataElement.ElementVisualType; } }
		/// <summary>
		/// Tvar elementu.
		/// </summary>
		public GraphElementShapeType ElementShapeType { get { return this.DataElement.ElementShapeType; } }
		/// <summary>
		/// Splnění úkolu, typicky u operací, které jsou částečně nebo zcela odvedeny.
		/// Zohledňuje se u grafu typu Gantt. (Typ grafu určuje RowGId (typ řádku).)
		/// Smysluplné hodnoty: 0 (= ještě se ani nezačalo) až 1 (= vše je hotovo). Hodnoty mimo rozsah 0 až 1 mají význam 0 nebo 1.
		/// </summary>
		public float CompletionRatio { get { return this.DataElement.CompletionRatio; } }
		/// <summary>
		/// Využití stavu kapacity v poměrné hodnotě (1.00 = 100%). Záporné hodnoty mají význam jako 0. 
		/// Hodnoty nad 1.00 značí přečerpání kapacit a zobrazují se.
		/// </summary>
		public float UtilizationRatio { get { return this.DataElement.UtilizationRatio; } }
		/// <summary>
		/// Poměrné využití výrobní linky pro tuto operaci (podílové využití)
		/// </summary>
		public float UseRatio { get { return this.DataElement.UseRatio; } }
		/// <summary> { get; }
		/// Číslo linkovací skupiny, typicky číslo subjektu ve vztahu "lcs.plan_unit_c_task.link".
		/// Hodnota 0 = není link, tento záznam není nijak spojen s jinými záznamy.
		/// </summary>
		public int LinkGroup { get { return this.DataElement.LinkGroup; } }
		/// <summary>
		/// Pozice elementu grafu v rámci aktuálního grafu řádku.
		/// Souřadnice X je relativní k aktuálnímu počátku grafu podle aktuálního počátku časové osy. Odpovídá času Begin. Může být záporná.
		/// Dimenze Width odpovídá době trvání elementu.
		/// Souřadnice Y je 1.
		/// Dimenze Height je dána výškou řádku - 2 (řeší se pouze GridLines).
		/// Tento údaj se aktualizuje pouze při posunech logických dat a při posunech časové osy a jejího měřítka.
		/// Při scrollování grafu nahoru/dolů se nemění.
		/// Při posouvání času doleva/doprava nebo změně časového měřítka se objekty přepočítávají.
		/// </summary>
		public Rectangle ElementArea { get; set; }
		/// <summary>
		/// Pozice detailu grafu = může být podmnožinou prostoru ElementArea.
		/// Typicky se využívá v grafu typu TaskCapacityLink pro zobrazení elementů typu TaskLink, v rámci konkrétní linky,
		/// viz příprava v metodě this._ChartElementsPrepareVisual().
		/// </summary>
		public Rectangle DetailArea { get; set; }
		/// <summary>
		/// Zobrazovaná pozice sub položky grafu Back (vykreslované pozadí). 
		/// Data jsou plněna jen pro určité typy grafů, viz metoda this.PrepareVisualDataForGraph() a návazné.
		/// Platné údaje jsou X, Width, Y, Height. 
		/// Pozice X a Y jsou relativní k pozici X,Y buňky, v níž se graf vykresluje.
		/// Rozměry Width a Height jsou v pixelech.
		/// Tento údaj se aktualizuje pouze při posunech logických dat a při posunech časové osy a jejího měřítka.
		/// Při scrollování grafu se nemění.
		/// </summary>
		public Rectangle RectangleBack { get; set; }
		/// <summary>
		/// Vrchol použité kapacity, nejvyšší souřadnice Y
		/// </summary>
		public int CapacityUsedTop { get; set; }
		/// <summary>
		/// Aktuální platná vizuální pozice položky grafu.
		/// Souřadnice jsou uvedeny v koordinátech Controlu, v němž je element vykreslen.
		/// Prostor je oříznutý do rozměrů aktuálního grafu (na rozdíl od ElementArea, který definuje pozici elementu v logickém prostoru grafu).
		/// Tento údaj se aktualizuje při každém vykreslení grafu.
		/// </summary>
		public Rectangle VisualRectangle { get; set; }
		/// <summary>
		/// Aktuální platná vizuální pozice položky grafu, vypočtená pro účely vykreslování různých vztahů.
		/// Počítá se i pro aktuálně neviditelné elementy a řádky, vychází z pozice ElementArea.
		/// </summary>
		public Rectangle RelationRectangle { get; set; }
		/// <summary>
		/// Příznak, že tento prvek grafu je nyní vhodné zobrazit.
		/// </summary>
		public bool Visible { get; set; }
		/// <summary>
		/// Příznak, že tento prvek grafu je právě v této době přenášený na jiný čas.
		/// V tuto chvíli se nachází v procesu editace, a je na jiném čase, než byl jeho původní čas (this.PreviousTimeRange).
		/// </summary>
		public bool CurrentlyMoved { get; set; }
		/// <summary>
		/// Příznak, že tento prvek grafu je právě v této době přenášený na jiný řádek.
		/// V tuto chvíli se nachází v procesu editace, a je na jiném řádku, než byl jeho původní řádek (this.PreviousRowGid).
		/// </summary>
		public bool CurrentlyTransposed { get; set; }
		/// <summary>
		/// Hodnota GID řádku, na kterém prvek bydlel před tím, než se s ním začalo pohybovat.
		/// </summary>
		public GID PreviousRowGid { get; set; }
		/// <summary>
		/// Hodnota TimeRange tohoto elementu, jaká byla na počátku editace před tím, než se s ním začalo pohybovat.
		/// </summary>
		public TimeRange PreviousTimeRange { get; set; }
		/// <summary>
		/// Příznak true, pokud je změněn čas elementu (this.TimeRange != this.PreviousTimeRange)
		/// </summary>
		public bool HasChangedTimeRange { get { return (this.TimeRange != this.PreviousTimeRange); } }
		/// <summary>
		/// Příznak true, pokud je změněn řádek elementu (this.RowGid != this.PreviousRowGid)
		/// </summary>
		public bool HasChangedRow { get { return (this.RowGid != this.PreviousRowGid); } }
		/// <summary>
		/// Příznak true, pokud je změněn čas nebo řádek elementu
		/// </summary>
		public bool HasChange { get { return (this.HasChangedTimeRange | this.HasChangedRow); } }
		/// <summary>
		/// Aktuální hodnota GID řádku
		/// </summary>
		public GID RowGid { get { return this.DataElement.RowGId; } set { this.DataElement.RowGId = value; } }
		/// <summary>
		/// Aktuální hodnota TimeRange elementu
		/// </summary>
		public TimeRange TimeRange { get { return this.DataElement.TimeRange; } set { this.DataElement.TimeRange = value; } }
		/// <summary>
		/// Příznak, že element se právě nyní nachází v editoru. Pak se s ním zachází jinak při výpočtech pro zobrazení.
		/// </summary>
		public bool IsInEditingState { get; set; }
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "{GraphElement: X=" + this.ElementArea.X.ToString() + "; Width=" + this.ElementArea.Width.ToString() + "; Data: " + this.DataElement.ToString() + "}";
		}
		/// <summary>
		/// Komparátor podle vizuálních priorit.
		/// Nejprve dává objekty "dospodu", a v rámci vrstvy je pak třídění podle času Begin
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static int CompareByVisualLayer(GraphElementDataCls a, GraphElementDataCls b)
		{
			int cl = ((int)a.DataElement.ElementLayer).CompareTo((int)b.DataElement.ElementLayer);
			if (cl != 0) return cl;

			int cb = a.DataElement.TimeRange.Begin.CompareTo(b.DataElement.TimeRange.Begin);
			if (cb != 0) return cb;

			int cp = a.DataElement.ParentWorkGId.CompareTo(b.DataElement.ParentWorkGId);
			if (cp != 0) return cp;

			int cw = a.DataElement.WorkGId.CompareTo(b.DataElement.WorkGId);
			if (cw != 0) return cw;

			int ce = a.DataElement.GId.CompareTo(b.DataElement.GId);
			return ce;
		}
		/// <summary>
		/// Komparátor podle vrstvy (v pořadí: TempLayer, SubLayer, ItemLayer) a podle času počátku (TimeRange.Begin).
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static int CompareByLayerBegin(GraphElementDataCls a, GraphElementDataCls b)
		{
			if (a.DataElement.ElementLayer != b.DataElement.ElementLayer)
				// Objekty na různých vrstvách: nižší vrstva bude dříve:
				return ((int)a.DataElement.ElementLayer).CompareTo((int)b.DataElement.ElementLayer);
			// Objekty na stejné vrstvě: objekt s nižším Begin bude dříve:
			return a.DataElement.TimeRange.Begin.CompareTo(b.DataElement.TimeRange.Begin);
		}
		/// <summary>
		/// Komparátor podle času počátku. Neřeší vrstvu ElementLayer.
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static int CompareByBegin(GraphElementDataCls a, GraphElementDataCls b)
		{
			// Objekty na stejné vrstvě: objekt s nižším Begin bude dříve:
			return a.DataElement.TimeRange.Begin.CompareTo(b.DataElement.TimeRange.Begin);
		}
		/// <summary>
		/// Komparátor podle vizuálních priorit.
		/// Nejprve dává objekty "dospodu", a v rámci vrstvy je pak třídění podle času Begin
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static int CompareByWorkGIdBegin(GraphElementDataCls a, GraphElementDataCls b)
		{
			if (a.DataElement.WorkGId != b.DataElement.WorkGId)
				// Objekty z různých WorkGID: 
				return (a.DataElement.WorkGId.CompareTo(b.DataElement.WorkGId));
			// Objekty ze stejného WorkGID: objekt s nižším Begin bude dříve:
			return a.DataElement.TimeRange.Begin.CompareTo(b.DataElement.TimeRange.Begin);
		}
		#endregion
		#region PROPERTY IsXxxx : zjistí, zda element má určitou vlastnost, na základě jeho hodnoty DataElement.ElementEditingMode
		/// <summary>
		/// Příznak, že tento element je fixní, není možno jej editovat (ani přesouvat, ani resizovat) ani selectovat.
		/// </summary>
		public bool IsDead { get { return !this.IsInteractive;; } }
		/// <summary>
		/// { get; } Obsahuje true, pokud objekt lze přesouvat na jiný čas = změnit jeho čas Begin a End (Movable).
		/// Pokud objekt není Movable, nelze s ním aktivně pohnout (myší).
		/// </summary>
		public bool IsMovable { get { return (MoveModeIsExact(this.DataElement.ElementEditingMode, DataElementEditingMode.Movable)); } }
		/// <summary>
		/// { get; } Obsahuje true, pokud objekt lze resizovat = změnit jeho šířku (Resizable)
		/// </summary>
		public bool IsResizable { get { return (MoveModeIsExact(this.DataElement.ElementEditingMode, DataElementEditingMode.Resizable)); } }
		/// <summary>
		/// { get; } Obsahuje true, pokud objekt lze přesouvat na jiný řádek = změnit jeho příslušnost z jednoho řádku na jiný.
		/// Pokud objekt není Transponable, pak musí zůstat na svém řádku.
		/// </summary>
		public bool IsTransponable { get { return (MoveModeIsExact(this.DataElement.ElementEditingMode, DataElementEditingMode.TransponableToAnotherRow)); } }
		/// <summary>
		/// { get; } Obsahuje true, pokud objekt je aktivní na pohyb myši, lze jej selectovat (Selectable).
		/// Netestuje (Movable | Resizable | TransponableToAnotherRow).
		/// </summary>
		public bool IsSelectable { get { return (this.DataElement.ElementLayer == GraphElementLayerType.ItemLayer && MoveModeIsAny(this.DataElement.ElementEditingMode, DataElementEditingMode.Selectable)); } }
		/// <summary>
		/// { get; } Obsahuje true, pokud objekt je aktivní na pohyb myši, lze jej selectovat, reaguje. 
		/// true je součet (Movable | Resizable | TransponableToAnotherRow | Selectable).
		/// 
		/// false = objekt se chová jako mrtvý brouk.
		/// </summary>
		public bool IsInteractive { get { return (this.DataElement.ElementLayer == GraphElementLayerType.ItemLayer && MoveModeIsAny(this.DataElement.ElementEditingMode, DataElementEditingMode.Movable | DataElementEditingMode.Resizable | DataElementEditingMode.TransponableToAnotherRow | DataElementEditingMode.Selectable)); } }
		/// <summary>
		/// Příznak, že tento element je přišpendlený = je jinak zobrazen, a při pohybu jím lze pohybovat pouze přímo.
		/// Pokud by bylo pohybováno sousedním elementem, pak tímto elementem to ani nepohne.
		/// Okolní elementy jej ale mohou překročit.
		/// Pokud máme tedy sadu elementů 10-20-30-40, a z toho element 30 je IsPinned, a pak pohnu elementem 10 doprava,
		/// pak to způsobí že se posune element 10, návazně element 20, který může přejít doprava i přes element 30 (který je IsPinned).
		/// Ale element 30 se nepohne, a proto se nepohne ani element 40 (ten je navázaný ke 30, a ta se nehýbá).
		/// Element 30 lze posunout jen přímým posunem.
		/// </summary>
		public bool IsPinned { get { return (MoveModeIsExact(this.DataElement.ElementEditingMode, DataElementEditingMode.PinnedItem)); } }
		/// <summary>
		/// Příznak, že tento element je blokující.
		/// S elementem tohoto typu lze pohybovat ručně, ale pokud dochází k pohybu v jeho okolí, pak se tento element nejen neposune, ale bude blokovat pohyb přes svou pozici.
		/// Chová se jako balvan na cestě.
		/// Pokud máme tedy sadu elementů 10-20-30-40, a z toho element 30 je IsBlocking, a pak pohnu elementem 10 doprava,
		/// pak to způsobí že se posune element 10, návazně element 20, ten ale (na rozdíl od IsPinned) nemůže obejít element 30,
		/// takže element 20 se zastaví na hraně elementu 30, čímž zabrzdí i element 10.
		/// Element 30 lze posunout jen přímým posunem.
		/// </summary>
		public bool IsBlocking { get { return (MoveModeIsExact(this.DataElement.ElementEditingMode, DataElementEditingMode.BlockingItem )); } }
		/// <summary>
		/// { get; } Obsahuje true, pokud objekt lze manuálně přesouvat nebo resizovat = lze jej aktivně měnit.
		/// true je součet (Movable | Resizable | TransponableToAnotherRow), ale ne Selectable.
		/// </summary>
		public bool IsEditable { get { return (this.DataElement.ElementLayer == GraphElementLayerType.ItemLayer && MoveModeIsAny(this.DataElement.ElementEditingMode, DataElementEditingMode.Movable | DataElementEditingMode.Resizable | DataElementEditingMode.TransponableToAnotherRow)); } }
		/// <summary>
		/// { get; } Obsahuje true, pokud objekt je pevně spojen se sousedními objekty (FixedLinkItemsOnSameThread)
		/// </summary>
		public bool IsJoinedToAdjacent { get { return (MoveModeIsExact(this.DataElement.ElementEditingMode, DataElementEditingMode.FixedLinkItemsOnSameThread)); } }
		/// <summary>
		/// { get; } Obsahuje true, pokud objekt je relativně svázán se sousedními objekty (ShiftItemsOnSameThread)
		/// </summary>
		public bool IsRelativeToAdjacent { get { return (MoveModeIsExact(this.DataElement.ElementEditingMode, DataElementEditingMode.ShiftItemsOnSameThread)); } }
		/// <summary>
		/// { get; } Obsahuje true, pokud objekt se při editaci snaží vracet na původní čas, pokud se tam volné místo.
		/// </summary>
		public bool IsAffinedToInitialTime { get { return (MoveModeIsExact(this.DataElement.ElementEditingMode, DataElementEditingMode.AffinityToInitialTime)); } }
		/// <summary>
		/// { get; } Obsahuje true, pokud tento objekt je prázdný. Svou prázdnotu odvozuje od this.DataElement.GId.IsEmpty.
		/// </summary>
		public bool IsEmpty { get { return this.DataElement.GId.IsEmpty; } }
		/// <summary>
		/// Příznak, že jde o Temporary prvek
		/// </summary>
		public bool IsTemporary { get { return (this.DataElement.ElementLayer == GraphElementLayerType.TempLayer); } }
		/// <summary>
		/// Příznak, že jde o prvek na vrstvě SubLayer
		/// </summary>
		public bool IsSubLayer { get { return (this.DataElement.ElementLayer == GraphElementLayerType.SubLayer); } }
		/// <summary>
		/// Příznak, že jde o prvek na vrstvě ItemLayer
		/// </summary>
		public bool IsItemLayer { get { return (this.DataElement.ElementLayer == GraphElementLayerType.ItemLayer); } }
		#endregion
		#region PODPORA DETEKCE STAVŮ TYPU DataElementEditingMode
		/// <summary>
		/// Jednoduchá detekční metoda pro Enum typu DataElementEditingMode [Flag]: zjistí, zda v hodnotě (editingMode)
		/// je nahozen bit(y) odpovídající hodnotě detectState. Vrací true, pokud v dané hodnotě je aktivní daný stav.
		/// Hodnota detectState je typicky základní, jednobitová.
		/// Hodnota detectState může být i vícebitová, pak funkce vrátí true jen pokud v dané hodnotě jsou nastaveny všechny bity.
		/// Pokud je jako detectState předána 0 (None), pak funkce vrací vždy true.
		/// </summary>
		/// <param name="editingMode">Typicky element.ElementEditingMode</param>
		/// <param name="detectState">Testovaný bit (bity).</param>
		/// <returns>true = testovaný bit je aktivní, je nahozen na 1 / false = neaktivní</returns>
		protected static bool MoveModeIsExact(DataElementEditingMode editingMode, DataElementEditingMode detectState)
		{
			return ((editingMode & detectState) == detectState);
		}
		/// <summary>
		/// Jednoduchá detekční metoda pro Enum typu DataElementEditingMode [Flag]: zjistí, zda v hodnotě (editingMode)
		/// je nahozen některý bit(y) odpovídající hodnotě detectState. Vrací true, pokud v dané hodnotě je aktivní alespoň jeden bit z daného stavu.
		/// Hodnota detectState je typicky kombinovaná, vícebitová.
		/// Hodnota detectState může být i jednobitová, pak funkce vrátí totéž jako funkce _ModeIsExact().
		/// Pokud je jako detectState předána 0 (None), pak funkce vrací vždy false.
		/// </summary>
		/// <param name="editingMode">Typicky element.ElementEditingMode</param>
		/// <param name="detectState">Testované bity (bit).</param>
		/// <returns>true = hodnota obsahuje přinejmenším jeden z testovaných bitů / false = ani jeden</returns>
		protected static bool MoveModeIsAny(DataElementEditingMode editingMode, DataElementEditingMode detectState)
		{
			return ((editingMode & detectState) > 0);
		}
		#endregion
		#region PODPORA KONFIGURACE TEXTU ELEMENTU A TOOLTIPU A VIZUÁLNÍCH VLASTNOSTÍ
		/// <summary>
		/// Titulek Tooltipu. Buď je získaný z konfigurovaných textů, anebo z elementu.
		/// </summary>
		public string TooltipTitle
		{
			get
			{
				string result = null;
				if (this.IsConfiguredText)
					result = this.EvaluatedTexts.TooltipTitle;
				if (String.IsNullOrEmpty(result))
					result = "Informace o položce";
				return result;
			}
		}
		/// <summary>
		/// Text Tooltipu. Buď je získaný z konfigurovaných textů, anebo z elementu.
		/// </summary>
		public string TooltipText
		{
			get
			{
				string result = null;
				if (this.IsConfiguredText)
					result = this.EvaluatedTexts.TooltipText;
				if (String.IsNullOrEmpty(result))
					result = this.DataElement.ToolTipInfo(this.DataRow);
				return result;
			}
		}
		/// <summary>
		/// Text Caption (= text v elementu), pro danou délku = počet znaků
		/// </summary>
		/// <param name="rowData">Data řádku</param>
		/// <param name="charCount">Počet standardních znaků, které se vejdou do grafu</param>
		/// <param name="charMeasureFunc">Funkce, která vrátí pro daný text (argument) poměrné naplnění elementu textem: 0=nic, 1=maximum, více než 1=nevejde se</param>
		/// <returns></returns>
		public string GetCaptionForLength(IDataRow rowData, float charCount, Func<string, float> charMeasureFunc)
		{
			string result = "";
			if (this.IsConfiguredText)
			{
				string[] captions = this.EvaluatedTexts.Captions;
				if (captions != null && captions.Length > 0)
				{
					float maxFill = 0f;
					string maxText = null;
					foreach (string caption in captions)
					{
						if (String.IsNullOrEmpty(caption)) continue;
						float fill = charMeasureFunc(caption);           // Poměrné vyplnění elementu tímto textem
						if (fill <= 1f && (maxText == null || fill > maxFill))
						{
							maxFill = fill;
							maxText = caption;
						}
					}
					result = maxText;
				}
			}

			if (String.IsNullOrEmpty(result))
				result = this.DataElement.Caption(rowData, charCount);
			return result;
		}
        /// <summary>
        /// Font pro element, pokud jej uživatel deklaroval (v okně Konfigurace textů).
        /// </summary>
        public Font FontForElement
        {
            get
            {
                if (this.IsConfiguredText)
                    return this.EvaluatedTexts.Font;
                return null;
            }
        }
        /// <summary>
        /// Barva pro text fontu elementu, pokud ji uživatel deklaroval (v okně Konfigurace textů).
        /// </summary>
        public Color FontColorForElement
        {
            get
            {
                if (this.IsConfiguredText)
                    return this.EvaluatedTexts.FontColor;
                return Color.Empty;
            }
        }
        /// <summary>
        /// Štětec pro text elementu, pokud ji uživatel deklaroval (v okně Konfigurace textů).
        /// </summary>
        public Brush FontBrushForElement
        {
            get
            {
                if (this.IsConfiguredText)
                    return this.EvaluatedTexts.FontBrush;
                return null;
            }
        }
        /// <summary>
        /// Barva pro text fontu elementu, pokud ji uživatel deklaroval (v okně Konfigurace textů).
        /// </summary>
        public ConfiguredVisibleMode VisibleModeForElement
        {
            get
            {
                if (this.IsConfiguredText)
                    return this.EvaluatedTexts.VisibleMode;
                return ConfiguredVisibleMode.Default;
            }
        }
        /// <summary>
        /// Určí, zda se má kreslit text do tohoto elementu, pokud je element v daném stavu
        /// </summary>
        /// <param name="graphElementState"></param>
        /// <returns></returns>
        public bool IsDrawCaptionOnState(GraphElementState graphElementState, RowGraphMode graphMode)
        {
            bool isActive = (graphElementState == GraphElementState.OnMouseFree ||
                             graphElementState == GraphElementState.OnMousePinned ||
                             graphElementState == GraphElementState.SelectedFree ||
                             graphElementState == GraphElementState.SelectedPinned ||
                             graphElementState == GraphElementState.InEditorFree ||
                             graphElementState == GraphElementState.InEditorPinned ||
                             graphElementState == GraphElementState.ActiveFree ||
                             graphElementState == GraphElementState.ActivePinned);

            ConfiguredVisibleMode visibleMode = (this.IsConfiguredText ? this.VisibleModeForElement : ConfiguredVisibleMode.Default);
            switch (visibleMode)
            {   // Jak si uživatel vybral v konfiguraci textů:
                case ConfiguredVisibleMode.VisibleAllways:
                    return true;
                case ConfiguredVisibleMode.Hidden:
                    return false;
                case ConfiguredVisibleMode.VisibleOnlyActive:
                    return isActive;
            }

            switch (this.DataElement.CaptionVisibility)
            {   // Pokud programátor v elementu definoval:
                case CaptionVisibilityMode.Always:
                    return true;
                case CaptionVisibilityMode.Hidden:
                    return false;
            }

            switch (graphMode)
            {   // Podle typu grafu:
                case RowGraphMode.NoDrawingElements:
                    return false;
                case RowGraphMode.Sector:
                    return false;
                case RowGraphMode.Gantt:
                    return true;
                case RowGraphMode.CapacityUtilization:
                    return false;
                case RowGraphMode.TaskCapacityLink:
                    return isActive;
                case RowGraphMode.StockReserve:
                    return isActive;
            }
            return false;
        }
        /// <summary>
		/// Aktuální hodnoty konfigurovaných textů.
		/// Obsahuje konkrétní texty pro tento element, ale pouze v případě kdy tento element je konfigurovatelný (this.IsConfiguredText je true).
		/// Obsahuje vždy aktuální data (to si zajišťují interní kontroly).
		/// </summary>
		public EvaluatedTexts EvaluatedTexts { get { return this._GetEvaluatedTexts(); } }
		/// <summary>
		/// (Weak)Reference na datový zdroj.
		/// Je nutno naplnit explicitně po vytvoření elementu.
		/// Typické plnění:
		/// if (element.IsConfiguredText)
		///		element.EvaluationDataSource = dataSource as IEvaluationDataSource;
		/// </summary>
		public IEvaluationDataSource EvaluationDataSource
		{
			get
			{
				if (this._EvaluationDataSourceWeak != null && this._EvaluationDataSourceWeak.IsAlive && this._EvaluationDataSourceWeak.Target is IEvaluationDataSource)
					return this._EvaluationDataSourceWeak.Target as IEvaluationDataSource;
				return null;
			}
			set
			{
				if (value != null)
					this._EvaluationDataSourceWeak = new WeakReference(value);
				else
					this._EvaluationDataSourceWeak = null;
			}
		}
		private WeakReference _EvaluationDataSourceWeak;
		/// <summary>
		/// Příznak true, pokud tento element je schopen konfigurovat svoje texty (je IConfiguredText a má ConfigurationKey not null).
		/// </summary>
		public bool IsConfiguredText { get { return (this._IConfiguredText != null && this._IConfiguredText.ConfigurationKey != null); } }
		/// <summary>
		/// Obsahuje klíč konfigurovaných textů = přečteno z this.DataElement.ConfigurationKey.
		/// Pokud je null, není element konfigurovatelný.
		/// </summary>
		protected string ConfigurationKey
		{
			get
			{
				if (!this.IsConfiguredText) return null;
				return this._IConfiguredText.ConfigurationKey;
			}
		}
		/// <summary>
		/// Příprava při inicializaci
		/// </summary>
		private void _PrepareConfiguredText()
		{
			this._IConfiguredText = this.DataElement as IConfiguredText;
			if (!this.IsConfiguredText) return;
		}
		/// <summary>
		/// Metoda, která zajistí aktuálnost dat v this._EvaluatedTexts
		/// </summary>
		/// <returns></returns>
		private EvaluatedTexts _GetEvaluatedTexts()
		{
			if (!this.IsConfiguredText) return null;
			bool isValid = (this._EvaluatedTexts != null);
			if (isValid)
				isValid = SchedulerConfigData.IsValid(Noris.Schedule.Support.Expressions.Constants.CONFIG_GROUP_TEXT, this.ConfigurationKey, this._EvaluatedTexts.Version);
			if (!isValid)
				this._EvaluatedTexts = Noris.Schedule.Support.Expressions.Evaluator.EvaluateText(this._IConfiguredText, this.EvaluationDataSource);
			return this._EvaluatedTexts;
		}
		private EvaluatedTexts _EvaluatedTexts;
		private IConfiguredText _IConfiguredText;
		#endregion
	}
	#endregion
}
